package gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.filechooser.FileFilter;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;

import tasks.UpdateProgressBar;
import tasks.UpdateSpeed;
import tools.Format;
import core.Executor;
import core.InvalidBEncodingException;
import core.Torrent;
import core.TorrentManager;

public class FenetrePrincipale extends JFrame implements KeyListener{

	private JFileChooser fc;
	/********** Table *************/
	private String title[] = {"Titre", "Progression", "DL Speed", "UL Speed", "Taille"};
	private Object data[][] = {};
	private DefaultTableModel model;
	private JTable table;
	/********** MenuBar *************/
	private JMenuBar menuBar;
	private JMenu fichier;
	private JMenuItem ouvrir;
	private JMenuItem ouvrirURL;
	private JMenuItem nouveau;
	private JMenu action;
	private JMenuItem stopAll;
	private JMenuItem clear;
	private JMenuItem quitter;
	/********** ToolBar *************/
	private JToolBar toolbar;
	private ClassLoader classLoader;
	private URL imAdd;
	private JButton add;
	private URL imAddUrl;
	private JButton addUrl;


	private URL imCreate;
	private JButton create;
	private JButton stop;
	private JButton start;
	private JButton option;
	private JButton about;
	/********** PanelInfo *************/
	private JPanel info;
	private JLabel dlSpeed;
	private JLabel upSpeed;
	/********** Torrent **************/
	private ExecutorService threadPool;

	public FenetrePrincipale() {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (UnsupportedLookAndFeelException e) {
			e.printStackTrace();
		}

		this.threadPool = Executor.getThreadPool();



		this.setTitle("BbqTorrent");
		this.setSize(600, 300);

		this.initMenu();
		this.initToolBar();
		this.initTable();
		this.initInfo();
		this.setIconImage(new ImageIcon(classLoader.getResource("images/bbq.png")).getImage());
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setLocationRelativeTo(null);
		this.setVisible(true);
	}

	private void initMenu() {

		this.fc = new JFileChooser();
		this.menuBar = new JMenuBar();
		this.fichier = new JMenu("Fichier");
		this.ouvrir = new JMenuItem("Ouvrir un fichier");
		this.ouvrirURL = new JMenuItem("Ajouter un fichier distant");
		this.nouveau = new JMenuItem("Créer");
		this.action = new JMenu("Action");
		this.stopAll = new JMenuItem("Tout arrêter");
		this.clear = new JMenuItem("Effacer");
		this.quitter = new JMenuItem("Quitter");

		this.ouvrir.addActionListener(new OpenListener());
		this.ouvrirURL.addActionListener(new OpenURLListener());
		this.nouveau.addActionListener(new CreateListener());
		this.quitter.addActionListener(new QuitListener());


		this.fichier.add(ouvrir);
		this.fichier.add(ouvrirURL);
		this.fichier.add(nouveau);
		this.fichier.add(new JSeparator());
		this.fichier.add(quitter);
		this.menuBar.add(fichier);

		this.action.add(stopAll);
		this.action.add(clear);
		this.menuBar.add(action);   

	}

	private void initToolBar() {

		this.toolbar = new JToolBar();
		this.classLoader = getClass().getClassLoader();
		this.imAdd = this.classLoader.getResource("images/add.png");
		this.add = new JButton(new ImageIcon(this.imAdd));
		this.imAddUrl = this.classLoader.getResource("images/addUrl.png");
		this.addUrl = new JButton(new ImageIcon(this.imAddUrl));
		this.imCreate = this.classLoader.getResource("images/create.png");
		this.create = new JButton(new ImageIcon(this.imCreate));
		this.start = new JButton (new ImageIcon(this.classLoader.getResource("images/play.png")));
		this.stop = new JButton(new ImageIcon(this.classLoader.getResource("images/stop.png")));
		this.option = new JButton(new ImageIcon(this.classLoader.getResource("images/option.png")));
		this.about = new JButton(new ImageIcon(this.classLoader.getResource("images/about.png")));

		this.add.addActionListener(new OpenListener());
		this.addUrl.addActionListener(new OpenURLListener());
		this.create.addActionListener(new CreateListener());
		this.option.addActionListener(new OptionListener());
		this.about.addActionListener(new AboutListener());

		this.add.setToolTipText("Ajouter un torrent");
		this.add.setBorder(null);
		this.add.setContentAreaFilled(false);
		this.addUrl.setToolTipText("Ajouter un torrent distant");
		this.addUrl.setBorder(null);
		this.addUrl.setContentAreaFilled(false);
		this.create.setToolTipText("Créer un torrent");
		this.create.setBorder(null);
		this.create.setContentAreaFilled(false);
		this.start.setToolTipText("Démarrer");
		this.start.setBorder(null);
		this.start.setContentAreaFilled(false);
		this.stop.setToolTipText("Arrêter");
		this.stop.setBorder(null);
		this.stop.setContentAreaFilled(false);
		this.option.setToolTipText("Option");
		this.option.setBorder(null);
		this.option.setContentAreaFilled(false);
		this.about.setToolTipText("A propos");
		this.about.setBorder(null);
		this.about.setContentAreaFilled(false);


		this.toolbar.add(add);
		this.toolbar.add(addUrl);
		this.toolbar.add(create);
		this.toolbar.add(start);
		this.toolbar.add(stop);
		this.toolbar.add(option);
		this.toolbar.add(about);
		this.toolbar.setFloatable(false);
		this.getContentPane().add(toolbar, BorderLayout.NORTH);

	}

	private void initTable() {

		this.model = new DefaultTableModel(this.data, this.title) {

			public boolean isCellEditable(int row, int col) {
				return false;
			}
		};
		this.table = new JTable(this.model);

		this.table.addKeyListener(this);

		this.table.getColumn(title[1]).setCellRenderer(new ProgressRenderer());        

		this.table.setRowHeight(40);
		this.table.setRowSorter(new TableRowSorter(this.model));
		this.table.addMouseListener(new MouseAdapter() {

			public void mouseReleased(MouseEvent event) {
				if (event.getButton() == event.BUTTON3) {
					if (FenetrePrincipale.this.table.columnAtPoint(new Point(event.getX(), event.getY())) != -1) {

						JMenuItem delete = new JMenuItem("Supprimer");
						JMenuItem stop = new JMenuItem("Arrêter");
						JMenuItem property = new JMenuItem("Propriétés");

						delete.addActionListener(new DeleteListener(new Point(event.getX(), event.getY())));
						property.addActionListener(new PropertyListener(new Point(event.getX(), event.getY())));
						stop.addActionListener(new StopListener(new Point(event.getX(), event.getY())));

						JPopupMenu menu = new JPopupMenu();
						menu.add(delete);
						menu.add(stop);
						menu.add(property);
						menu.show(FenetrePrincipale.this.table, event.getX(), event.getY());
					}
				}
			}
		});

		this.getContentPane().add(new JScrollPane(this.table), BorderLayout.CENTER);
	}

	private void initInfo() {

		this.info = new JPanel();
		this.dlSpeed = new JLabel();
		this.upSpeed = new JLabel();

		this.info.setLayout(new FlowLayout());
		this.dlSpeed.setText("DL : 0.0 ko/s");
		this.upSpeed.setText("UP : 0.0 ko/s");

		this.info.add(dlSpeed);
		this.info.add(upSpeed);

		this.getContentPane().add(info, BorderLayout.SOUTH);

		UpdateSpeed task = new UpdateSpeed();
		task.addPropertyChangeListener(
				new PropertyChangeListener() {            	    	
					public  void propertyChange(PropertyChangeEvent evt) {
						if ("totalUp".equals(evt.getPropertyName())) {
							FenetrePrincipale.this.upSpeed.setText("up:"+((String) evt.getNewValue()));
						}

						if ("totalDown".equals(evt.getPropertyName())) {
							FenetrePrincipale.this.dlSpeed.setText("down:"+((String) evt.getNewValue()));
						}

						if ("upSpeed".equals(evt.getPropertyName())) {
							for(int i=0; i<FenetrePrincipale.this.model.getRowCount(); i++) {
								if(((String)FenetrePrincipale.this.model.getValueAt(i, 0)).equals((String) evt.getOldValue())) {
									FenetrePrincipale.this.model.setValueAt((String)evt.getNewValue(), i, 3);
								}
							}
						}

						if ("downSpeed".equals(evt.getPropertyName())) {
							for(int i=0; i<FenetrePrincipale.this.model.getRowCount(); i++) {
								if(((String)FenetrePrincipale.this.model.getValueAt(i, 0)).equals((String) evt.getOldValue())) {
									FenetrePrincipale.this.model.setValueAt((String)evt.getNewValue(), i, 2);
								}
							}
						}
					}			
				});

		this.threadPool.execute(task);
	}

	class DeleteListener implements ActionListener {

		private Point point = null;

		public DeleteListener(Point p) {
			this.point = p;
		}

		public void actionPerformed(ActionEvent e) {
			int row = table.rowAtPoint(point);
			String name = (String)FenetrePrincipale.this.model.getValueAt(row, 0);            
			TorrentManager.getInstance().removeTorrent(name);

			FenetrePrincipale.this.model.removeRow(row);
		}
	}

	class PropertyListener implements ActionListener {

		private Point point = null;

		public PropertyListener(Point p) {
			this.point = p;
		}

		public void actionPerformed(ActionEvent e) {
			int row = table.rowAtPoint(point);
			Torrent torrent = TorrentManager.getInstance().find((String) ((DefaultTableModel) table.getModel()).getValueAt(row, 0));
			FenetreProperty prop = new FenetreProperty(torrent);
		}
	}

	class OpenListener implements ActionListener {

		public void actionPerformed(ActionEvent e) {
			fc.setDialogTitle("Ouvrir");
			fc.setApproveButtonText("Ouvrir");
			FileFilter filter = new FileFilter(){
				public boolean accept(File f){
					return ((f.isDirectory()) && (f.getName().endsWith(".torrent")));
				}
				public String getDescription(){
					return "Torrent file";
				}
			};

			FiltreSimple fs = new FiltreSimple("torrent", ".torrent");
			fc.setFileFilter(fs);
			int returnVal = fc.showOpenDialog(null);
			if (returnVal == JFileChooser.APPROVE_OPTION) {
				try {
					if (fc.getSelectedFile().getName().endsWith(".torrent")) {
						try {
							FenetrePrincipale.this.addTorrent(fc.getSelectedFile());                          

						} catch (InterruptedException ex) {
							Logger.getLogger(FenetrePrincipale.class.getName()).log(Level.SEVERE, null, ex);
						} catch (ExecutionException ex) {
							Logger.getLogger(FenetrePrincipale.class.getName()).log(Level.SEVERE, null, ex);
						}
					} else {

						MessageErreur me = new MessageErreur("Ce n'est pas un fichier torrent");
						me.setLocationRelativeTo(FenetrePrincipale.this.getContentPane());

					}
				} catch (FileNotFoundException e1) {
					
					e1.printStackTrace();
				} catch (IOException e1) {
					
					e1.printStackTrace();
				} catch (InvalidBEncodingException e1) {
					
					e1.printStackTrace();
				}

			}
		}
	}

	class OptionListener implements ActionListener {

		public void actionPerformed (ActionEvent e){
			FenetrePrincipale.this.option.setEnabled(false);
			FenetreOption fo = new FenetreOption(FenetrePrincipale.this);
			fo.setLocationRelativeTo(FenetrePrincipale.this.getContentPane());

		}
	}

	class OpenURLListener implements ActionListener {

		public void actionPerformed(ActionEvent e) {
			FenetrePrincipale.this.addUrl.setEnabled(false);
			FenetreAddUrl url = new FenetreAddUrl(FenetrePrincipale.this);
			url.setLocationRelativeTo(FenetrePrincipale.this.getContentPane());
		}
	}

	class StopListener implements ActionListener {

		private Point point = null;
		private DefaultTableCellRenderer rend = new DefaultTableCellRenderer();

		public StopListener(Point p) {
			this.point = p;
		}

		public void actionPerformed(ActionEvent e) {
			int row = table.rowAtPoint(point);
		}
	}

	class CreateListener implements ActionListener {

		public void actionPerformed(ActionEvent e) {
			FenetrePrincipale.this.create.setEnabled(false);
			FenetreCreate fc = new FenetreCreate(FenetrePrincipale.this);
		}
	}

	class AboutListener implements ActionListener {
		public void actionPerformed(ActionEvent e){
			final JFrame about = new JFrame("A propos");
			about.setLocationRelativeTo(null);
			JButton ok = new JButton("OK");
			JPanel content = new JPanel();
			JTextArea text = new JTextArea();
			text.setSize(400, 50);
			text.setBackground(new Color(240,240,240));
			text.setWrapStyleWord(true);

			text.setText("BBQTorrent est un client torrent réalisé par Dimitri Ségard, Geoffrey Groff et Cyril Ly,\n dans le cadre d'un projet de fin d'année");
			ok.addActionListener(new ActionListener(){
				public void actionPerformed(ActionEvent e){
					FenetrePrincipale.this.about.setEnabled(true);
					about.dispose();
				}
			});
			text.setLineWrap(true);
			text.setEditable(false);
			content.setSize(300,100);
			content.add(text, BorderLayout.CENTER);
			content.add(ok, BorderLayout.SOUTH);

			about.setContentPane(content);
			about.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
			about.setSize(400, 120);
			about.setVisible(true);
			about.setResizable(false);
			FenetrePrincipale.this.about.setEnabled(false);


		}
	}

	class ProgressRenderer extends DefaultTableCellRenderer {


		private final JProgressBar myProgressBar = new JProgressBar(0, 100);

		public ProgressRenderer() {
			super();
			setOpaque(true);
			myProgressBar.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
			myProgressBar.setStringPainted(true);

		}

		@Override
		public Component getTableCellRendererComponent(JTable table, Object value,
				boolean isSelected, boolean hasFocus,
				int row, int column) {
			Integer i = (Integer) value;
			String text = "Fait";
			if (i < 0) {
				text = "Annulé";
			} else if (i < 100) {
				myProgressBar.setValue(i);
				return myProgressBar;
			}
			super.getTableCellRendererComponent(table, text, isSelected, hasFocus, row, column);
			return this;
		}
	}

	private void displayTorrent(Torrent torrent) {
		System.out.println(torrent);

		double size = (double) torrent.getLength();
		Object[] t = {torrent.getName(), 0, "0", "0", Format.bytes(size)};
		FenetrePrincipale.this.model.addRow(t);

	}

	public void addTorrent(File file) throws InvalidBEncodingException, IOException, InterruptedException, ExecutionException {
		final Torrent torrent = TorrentManager.getInstance().addTorrent(file);

		UpdateProgressBar task = new UpdateProgressBar(torrent);
		task.addPropertyChangeListener(
				new PropertyChangeListener() {            	    	
					public  void propertyChange(PropertyChangeEvent evt) {
						if ("progress".equals(evt.getPropertyName())) {
							for(int i=0; i<FenetrePrincipale.this.model.getRowCount(); i++) {
								if(((String)FenetrePrincipale.this.model.getValueAt(i, 0)).equals(torrent.getName())) {
									FenetrePrincipale.this.model.setValueAt((Integer)evt.getNewValue(), i, 1);
								}
							}
						}
					}			
				});

		FenetrePrincipale.this.threadPool.execute(task);

		this.displayTorrent(torrent);
	}

	public void addTorrent(String path) throws InvalidBEncodingException, IOException, InterruptedException, ExecutionException {
		Torrent torrent = TorrentManager.getInstance().addTorrent(path);
		this.displayTorrent(torrent);
	}

	class QuitListener implements ActionListener {

		JFrame frame;

		public void actionPerformed(ActionEvent e) {

			frame = new JFrame("Quitter");
			JPanel content = new JPanel();
			JLabel text = new JLabel("Voulez-vous vraiment quitter ?");
			JButton ok = new JButton("OK");
			JButton cancel = new JButton("Annuler");

			frame.setLocationRelativeTo(null);

			ok.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent e) {
					frame.dispose();
					FenetrePrincipale.this.dispose();
				}
			});

			cancel.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent e) {
					frame.dispose();
				}
			});

			content.add(text, BorderLayout.NORTH);
			content.add(ok, BorderLayout.SOUTH);
			content.add(cancel, BorderLayout.SOUTH);

			frame.add(content);
			frame.setSize(200, 100);
			frame.setResizable(false);
			frame.setVisible(true);
		}
	}

	public JButton getAddUrl() {
		return addUrl;
	}

	public JButton getCreate() { 
		return create;
	}

	public JButton getOption() {
		return option;
	}

	@Override
	public void keyPressed(KeyEvent arg0) {
		

	}

	@Override
	public void keyReleased(KeyEvent arg0) {
		if (arg0.getKeyCode()==KeyEvent.VK_DELETE){
			int row = FenetrePrincipale.this.table.getSelectedRow();
			String name = (String)FenetrePrincipale.this.model.getValueAt(row, 0);
			TorrentManager.getInstance().removeTorrent(name);

			FenetrePrincipale.this.model.removeRow(row);

		}
	}

	@Override
	public void keyTyped(KeyEvent arg0) {
		

	}
}
